/************ inverse.cpp
  rsc, 04.05.2013-30.04.2014
  inverse file contents
*/

//We support large file (64-bit offset)
#define _LARGEFILE64_SOURCE

#include<stdio.h>

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>

#define BUFSIZE 65536

#define _DEBUG

int main (int argc,char ** argv)
{
  if (argc==1)
  {
    puts ("This is inverse, RSC: 04.05.2013-30.04.2014");
    puts ("inverse inverse all file content");
//    printf ("Offset size: %d",sizeof(off64_t));
    puts ("./inverse <filename>");
  } else
  {
    int fd=open (argv[1],O_LARGEFILE|O_RDWR);
    if (fd==-1)
    {
      puts ("Error: cannot open file");
    } else
    {
      //File is opened with file descriptor fd
     
      off64_t curpos=0;
      ssize_t res;
      off64_t res_seek;
      do
      {
        char buf[BUFSIZE];
        res_seek=lseek64 (fd,curpos,SEEK_SET);
        if (res_seek!=-1)
        {
          res=read (fd,buf,BUFSIZE);
          //res is count bytes from file
          if (res>0)
          {
            #ifdef _DEBUG
            printf ("Read block from offset %llu size %u\n",(unsigned long long)curpos,(unsigned)res);
            #endif
      	    for (int i=0;i<res;i++) buf[i]=~buf[i];
      	    res_seek=lseek64 (fd,curpos,SEEK_SET);
      	    if (res_seek!=-1)
      	    {
    	      ssize_t res2=write (fd,buf,res);
    	      //Если записали меньше, чем прочли, то ясно, что ошибка
    	      if (res2<res) 
    	      {
    	        puts ("Error while writing");
    	        res=-1;
    	      } else
    	      {
                #ifdef _DEBUG
                printf ("Write block from offset %llu size %u\n",(unsigned long long) curpos,(unsigned)res);
                #endif
    	      }
    	      curpos+=res;
    	    } else
    	    {
    	      res=-1;
    	      puts ("Error while seeking for write");
    	    }
          }
        } else
        {
          res=-1;
          puts ("Error while seeking for read");
        }
        
      } while (res==BUFSIZE);
      if (res<0)
      {
        puts ("Error until reading and writing");
      } else
      {
        puts ("All OK");
      }
      close (fd);
    }
  }
}